package com.netty.common;

import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.cors.CorsConfig;
import io.netty.handler.codec.http.cors.CorsConfigBuilder;
import io.netty.handler.codec.http.cors.CorsHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.util.concurrent.*;

import javax.net.ssl.SSLEngine;


/**
 * 自定义Initializer
 * 实现http、https,客户端、服务器
 * @author gjj
 */
public class MyInitializer extends ChannelInitializer<Channel> {

    private boolean client;
    private SslContext sslContext;
    private SimpleChannelInboundHandler simpleChannelInboundHandler;

    private static final DefaultEventExecutorGroup eventExecutors = new DefaultEventExecutorGroup(8);

    public MyInitializer(SimpleChannelInboundHandler simpleChannelInboundHandler,
                         boolean client,boolean ssl)throws Exception{
        this.client=client;
        this.simpleChannelInboundHandler=simpleChannelInboundHandler;
        if(ssl){
            //开启ssl
            if(client){
                sslContext = SslContextBuilder.forClient()
                        .trustManager(InsecureTrustManagerFactory.INSTANCE).build();
            }else{
                SelfSignedCertificate ssc = new SelfSignedCertificate();
                sslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
            }

        }
    }

    @Override
    protected void initChannel(Channel channel) {
        try{
            ChannelPipeline pipeline = channel.pipeline();
            CorsConfig corsConfig = CorsConfigBuilder.forAnyOrigin().allowNullOrigin().allowCredentials()
                    .build();
            //获取ssl引擎，放置管道第一位
            //确保所有其他 ChannelHandler 应用他们的逻辑到数据后加密后才发生,
            //从而确保他们的变化是安全的。
            if(sslContext!=null){
                SSLEngine sslEngine = sslContext.newEngine(channel.alloc());
                pipeline.addFirst("ssl",new SslHandler(sslEngine));
            }
            if(client){
                //客户端模式
                pipeline.addLast("codec", new HttpClientCodec());

                pipeline.addLast("inflater",new HttpContentDecompressor());

                //大文件传输
                pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());


                pipeline.addLast("handler",simpleChannelInboundHandler.getClass().newInstance());

            }else{
                //服务端模式
                pipeline.addLast("codec", new HttpServerCodec());
                //跨域
//                pipeline.addLast(new CorsHandler(corsConfig));

                pipeline.addLast("inflater",new HttpContentCompressor());

                pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());

                //耗时任务交给EventExecutorGroup线程池处理
                //优点: 从而达到不阻塞io线程
                //缺点: 上传效率没有下方的高(主要有业务线程池的线程数决定)
                //      上传文件会容易造成direct memory内存泄露(暂时还没找到解决方案)
                //      增加了线程的切换
//                pipeline.addLast(eventExecutors,"handler",simpleChannelInboundHandler);

                //不使用业务线程，
                // 不会有线程切换的开销
                // 缺点业务都在io线程中会处理，会造成io线程的阻塞
                pipeline.addLast("handler",simpleChannelInboundHandler.getClass().newInstance());
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
